assume cs:code

code segment
start:			;将操作系统的7c号中断的入口地址移动到0000:0200处
				mov ax, 0
				mov ds, ax
				mov bx, 200h
				mov ax, ds:[4 * 124]; ip, 7c = 124
				mov ds:[bx], ax
				mov ax, ds:[4 * 124 + 2]; cs
				mov ds:[bx + 2], ax

				;将自己写的my7c移动到0000:0204处
				mov ax, cs
				mov ds, ax
				mov si, offset my7c
				mov ax, 0
				mov es, ax
				mov di, 204h
				mov cx, offset my7c_end - offset my7c
				cld ;设置si，di递增
				rep movsb

				;将自己写的my7c设置到中断向量表中
				mov ax, 0
				mov ds, ax
				mov word ptr ds:[4 * 124], 204h ;ip
				mov word ptr ds:[4 * 124 + 2], 0 ;cs

				;修改0000:0206开始的8个字节,原来的偏移是相对于start(也就是0)的，移动到0000:0204开始的地方的时候，需要从204开始算起
				;画个图就知道了为什么要先减 offset my7c，然后再加上204h, 一个是从0开始的，一个是从my7c开始的
				mov ax, 0
				mov ds, ax
				mov bx, 206h
				mov cx, 4				
start_s:		mov ax, offset my7c
				sub ds:[bx], ax
				add word ptr ds:[bx], 204h
				add bx, 2
				loop start_s


				;开始调用中断
				mov ah, 3
				mov al, 1
				int 7ch
				mov ax, 4c00h
				int 21h


;自己编写的7ch中断， ah功能号 0--清屏 1--设置前景色 2--设置背景色 3--向上滚动一行
;al传送颜色 值为0, 1, 2, 3, 4, 5, 6, 7中的一个
my7c:			jmp short my7cRealStart ;指令长度是2
fun_table		dw clear_screen, set_foreground, set_background, scroll_up
my7cRealStart:	push es
				push bx

				;检查ah参数，不符合要求直接结束
				cmp ah, 0
				jb my7c_exit
				cmp ah, 3
				ja my7c_exit

				;检查al参数，不符合要求直接结束
				;cmp al, 0
				;jb my7c_exit
				;cmp al, 7
				;ja my7c_exit


				mov bl, ah
				mov bh, 0
				add bx, bx ;关键的一步，没有这一步取出来的地址是错误的
				;call word ptr cs:fun_table[bx] ;这样写是错误的，因为编译的时候，将cs:fun_table[bx]编译成了cs:[bx + 44],当指令换了位置之后偏移不再是44了
				call word ptr cs:[bx + 206h] ;my7c安装的地方的起始偏移是204h，jmp short my7cRealStart指令的长度是2，因此偏移是206

my7c_exit:		pop bx
				pop es
				iret


;清屏的子程序
clear_screen:	push es	
				push cx
				push bx

				mov bx, 0b800h
				mov es, bx
				mov cx, 2000 ;25 * 80 = 2000
				mov bx, 0
cls_s:			mov byte ptr es:[bx], ' ' ;使用空格填充
				add bx, 2 ;只将字符位设置为' ',属性位使用默认的即可
				loop cls_s

				pop bx
				pop cx
				pop es
				ret	


;设置前景色的子程序
set_foreground:	push es
				push bx
				push cx

				mov bx, 0b800h
				mov es, bx
				mov bx, 1 ;属性位都是奇数
				mov cx, 2000
set_f_s:		and byte ptr es:[bx], 11111000b
				or byte ptr es:[bx], al
				add bx, 2
				loop set_f_s

				pop cx
				pop bx
				pop es
				ret



;设置背景色的子程序
set_background:	push es
				push bx
				push cx

				mov bx, 0b800h
				mov es, bx
				mov bx, 1 ;属性位都是奇数
				mov cx, 2000
set_b_s:		and byte ptr es:[bx], 10001111b
				or byte ptr es:[bx], al
				add bx, 2
				loop set_b_s

				pop cx
				pop bx
				pop es
				ret	



;向上滚动一行的子程序
scroll_up:		push es
				push bx
				push cx
				push si
				push di
				

				mov bx, 0b800h
				mov ds, bx
				mov es, bx
				mov si, 160
				mov di, 0

				mov cx, 25 ;25行
s_u_s:			push cx			
				mov cx, 160
				cld ;设置si，di递增
				rep movsb ;rep执行完毕之后本身就会改变si和di的值，si和di的值都会加160
				;add si, 160
				;add di, 160
				pop cx
				loop s_u_s

				;将最后一行都设置成' '
				mov cx, 160
				mov si, 0
s_u_last:		mov byte ptr es:[24 * 160 + si], ' '
				inc si
				loop s_u_last

				
				pop di
				pop si
				pop cx
				pop bx
				pop es
				ret

my7c_end:		nop



code ends

end start

